 /* 
  * Copyright (C) 2012 maxim 
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
  */

#include "tests.h"
#include <stdlib.h>
#include <assert.h>
static void print_to_screen(char* str)
{
	int count = 0,writed = 0;
	int len = strlen(str);
	while (count != len) {
		writed = uthread_write(1,str+count,sizeof(char)*(len-count));
		if (writed	>=	0)
			count += writed;
	}
	return;
}

static char* itoa(int num)
{
	if	(num == 0) 
		return "0";
	int num_digits=0,i=1;
	while (i <= num) {
		num_digits++;
		i *= 10;
	}
	char* str = (char*)malloc((num_digits+1)*sizeof(char));
	char tmp;
	str[num_digits] = '\0';
	for (i = (num_digits-1); i >= 0; i--){
		tmp = (char)(num % 10) + '0';
		num /= 10;
		str[i] = tmp;
	}
	return str;
}

static void block(uthread_mutex_t mutex) 
{
	if (uthread_mutex_lock(mutex) != MUTEX_SUCCESS) {
		print_to_screen("Unable to lock mutex.\n");
		exit(-1);
	}
}

static void unblock(uthread_mutex_t mutex) 
{
	if (uthread_mutex_unlock(mutex) != MUTEX_SUCCESS) {
		print_to_screen("Unable to unlock mutex.\n");
		exit(-1);
	}
}

static inline void delay(int n, char c) {
	int i;
	for (i = 0 ; i < n ; i++)
		i=i;
}

static inline void reset_counter()
{
	counter = 0;
}

static void msg_with_expected_order(int i, char * in, int id){
		block(print_mutex);
		print_to_screen(itoa(i));
	  print_to_screen(": ");
		print_to_screen("Thread Id= ");
		print_to_screen(itoa(id));
		print_to_screen("   ");
		print_to_screen(in);
		print_to_screen("\n");
		unblock(print_mutex);
}

static void msg(char * in){
	msg_with_expected_order(1,in,uthread_self());
}
static uthread_mutex_t mutex1;
static uthread_mutex_t mutex2;

/* Creates a circular thread wait using mutex
 * Its almost a deadlock, but since thread 0 is running it can cancel both threads */


static int thread1(void* arg)
{
	uthread_mutex_lock(mutex1);
	uthread_yield();
	uthread_mutex_lock(mutex2);
	return 1;

}

static int thread2(void* arg)
{
	uthread_mutex_lock(mutex2);
	uthread_mutex_lock(mutex1);
	return 2;
}


void test6()
{
	msg("\n******************Running test #6...*************");
	int ret;

	assert(uthread_mutex_init(&mutex1) == MUTEX_SUCCESS);
	assert(uthread_mutex_init(&mutex2) == MUTEX_SUCCESS);

	assert(uthread_create(thread1, NULL) == 1);
	assert(uthread_create(thread2, NULL) == 2);
	uthread_yield();
	uthread_yield();


	assert(uthread_cancel(1) == UTHREAD_SUCCESS);
	assert(uthread_cancel(2) == UTHREAD_SUCCESS);

	assert (uthread_join(1, &ret) == UTHREAD_SUCCESS);
	assert (ret == UTHREAD_CANCELLED);
	assert (uthread_join(2, &ret) == UTHREAD_SUCCESS);
	assert (ret == UTHREAD_CANCELLED);

	assert(uthread_cancel(1) == UTHREAD_INVALID);
	assert(uthread_cancel(2) == UTHREAD_INVALID);

	uthread_mutex_destroy(mutex1);
	/* don't destroy mutex2 on purpose... just in case*/
}
